package com.enation.app.javashop.core.goods.service.impl;

import com.enation.app.javashop.core.base.CachePrefix;
import com.enation.app.javashop.core.base.rabbitmq.AmqpExchange;
import com.enation.app.javashop.core.goods.GoodsErrorCode;
import com.enation.app.javashop.core.goods.model.dos.TagGoodsDO;
import com.enation.app.javashop.core.goods.model.dos.TagsDO;
import com.enation.app.javashop.core.goods.model.dto.TagsDTO;
import com.enation.app.javashop.core.goods.model.enums.*;
import com.enation.app.javashop.core.goods.model.vo.GoodsSelectLine;
import com.enation.app.javashop.core.goods.model.vo.GoodsTagVO;
import com.enation.app.javashop.core.goods.model.vo.TagGoodsNum;
import com.enation.app.javashop.core.goods.service.TagsManager;
import com.enation.app.javashop.framework.cache.Cache;
import com.enation.app.javashop.framework.context.UserContext;
import com.enation.app.javashop.framework.database.DaoSupport;
import com.enation.app.javashop.framework.database.IntegerMapper;
import com.enation.app.javashop.framework.database.Page;
import com.enation.app.javashop.framework.entity.DictDTO;
import com.enation.app.javashop.framework.exception.ServiceException;
import com.enation.app.javashop.framework.security.model.Seller;
import com.enation.app.javashop.framework.util.*;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 商品标签业务类
 *
 * @author fk
 * @version v2.0
 * @since v7.0.0
 * 2018-03-28 14:49:36
 */
@Service
public class TagsManagerImpl implements TagsManager {

    @Autowired
    @Qualifier("goodsDaoSupport")
    private DaoSupport daoSupport;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private Cache cache;


    @Override
    public Page list(GoodsTagVO goodsTagVO, int page, int pageSize) {

        Seller seller = UserContext.getSeller();

        String sql = "select * from es_tags  where seller_id = ?";
        if (!StringUtil.isEmpty(goodsTagVO.getTagName())) {
            sql = sql.concat(" and tag_name like '%" + goodsTagVO.getTagName() + "%'");
        }
        if (!StringUtil.isEmpty(goodsTagVO.getColor())) {
            sql = sql.concat(" and color = '" + goodsTagVO.getColor() + "'");
        }
        if (!StringUtil.isEmpty(goodsTagVO.getStyle())) {
            sql = sql.concat(" and style = '" + goodsTagVO.getStyle() + "'");
        }
        if (goodsTagVO.getShopHomePage() != null) {
            sql = sql.concat(" and shop_home_page = " + goodsTagVO.getShopHomePage());
        }
        if (goodsTagVO.getGoodsListPage() != null) {
            sql = sql.concat(" and goods_list_page = " + goodsTagVO.getGoodsListPage());
        }
        if (goodsTagVO.getGoodsDetailsPage() != null) {
            sql = sql.concat(" and goods_details_page = " + goodsTagVO.getGoodsDetailsPage());
        }
        if (goodsTagVO.getStartTime() != null) {
            sql = sql.concat(" and start_time >= " + goodsTagVO.getStartTime());
        }
        if (goodsTagVO.getEndTime() != null) {
            sql = sql.concat(" and end_time <= " + goodsTagVO.getEndTime());
        }
        sql = sql.concat(" and `status` != " + GoodsTagStatus.DELETE.getIndex() + " order by update_time desc ");
        Page webPage = this.daoSupport.queryForPage(sql, page, pageSize, TagsDO.class, seller.getSellerId());
        List<TagsDO> tagsDOList = webPage.getData();
        //返回给前端的List
        List<GoodsTagVO> goodsTagVOList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(tagsDOList)) {
            List<DictDTO> colorList = DictUtils.getDictList(null, "goods_tag_color");
            Map<String, String> colorMap = colorList.stream().collect(Collectors.toMap(DictDTO::getValue, DictDTO::getLabel));
            List<DictDTO> styleList = DictUtils.getDictList(null, "goods_tag_style");
            Map<String, String> styleMap = styleList.stream().collect(Collectors.toMap(DictDTO::getValue, DictDTO::getLabel));
            List<DictDTO> typeList = DictUtils.getDictList(null, "goods_tag_type");
            Map<String, String> typeMap = typeList.stream().collect(Collectors.toMap(DictDTO::getValue, DictDTO::getLabel));
            for (TagsDO tagsDO : tagsDOList) {
                GoodsTagVO resultVO = new GoodsTagVO();
                BeanUtil.copyProperties(tagsDO, resultVO);
                //封装给返回给前端的标签展示位置列表
                List<String> tagDisPosList = new ArrayList<>();
                if (tagsDO.getShopHomePage() == null || tagsDO.getShopHomePage() == GoodsTagPageStatus.SHOW.getIndex()) {
                    tagDisPosList.add(GoodsTagDisplayPosition.SHOP_HOME_PAGE.getDescribe());
                }
                if (tagsDO.getGoodsListPage() == null || tagsDO.getGoodsListPage() == GoodsTagPageStatus.SHOW.getIndex()) {
                    tagDisPosList.add(GoodsTagDisplayPosition.GOODS_LIST_PAGE.getDescribe());
                }
                if (tagsDO.getGoodsDetailsPage() == null || tagsDO.getGoodsDetailsPage() == GoodsTagPageStatus.SHOW.getIndex()) {
                    tagDisPosList.add(GoodsTagDisplayPosition.GOODS_DETAILS_PAGE.getDescribe());
                }
                resultVO.setGoodsTagDisplayPosition(tagDisPosList);
                resultVO.setColorName(StringUtil.isEmpty(tagsDO.getColor()) ? "" : colorMap.get(tagsDO.getColor()));
                resultVO.setStyleName(StringUtil.isEmpty(tagsDO.getStyle()) ? "" : styleMap.get(tagsDO.getStyle()));
                resultVO.setTypeName(tagsDO.getType() == null ? "" : typeMap.get(tagsDO.getType().toString()));
                goodsTagVOList.add(resultVO);
            }
        }
        webPage.setData(goodsTagVOList);
        return webPage;
    }

    //新增和修改商品标签
    @Override
    public void addAndEditGoodsTags(GoodsTagVO goodsTagVO) {
        if (goodsTagVO == null) {
            throw new ServiceException("601", "参数异常");
        }

        String tagName = goodsTagVO.getTagName();
        if (StringUtil.isEmpty(tagName)) {
            throw new ServiceException("601", "参数异常");
        }

        Integer sellerId = UserContext.getSeller().getSellerId();

        //判断同一家店铺中是否有重复的标签名
        String tagsSql = "select * from es_tags where seller_id = " + sellerId + " and `status` != " + GoodsTagStatus.DELETE.getIndex();
        Integer tagId = goodsTagVO.getTagId();
        if (tagId != null) {
            //修改
            tagsSql = tagsSql.concat(" and tag_id != " + tagId);
        }
        List<TagsDO> tagsDOList = this.daoSupport.queryForList(tagsSql, TagsDO.class);
        if (!CollectionUtils.isEmpty(tagsDOList)) {
            Map<String, TagsDO> map = tagsDOList.stream().collect(Collectors.toMap(TagsDO::getTagName, Function.identity(), (oldValue, newValue) -> newValue));
            if (map.get(tagName) != null) {
                throw new ServiceException("602", "标签名重复");
            }
        }

        if (tagId != null) {
            //1、修改标签信息
            //获取老的tag
            TagsDO oldTags = this.daoSupport.queryForObject(TagsDO.class, tagId);
            if (oldTags.getType() != GoodsTagType.CUSTOM.getIndex()) {
                throw new ServiceException("603", "系统默认标签不能修改");
            }
            //要保存的标签
            TagsDO newTag = new TagsDO();
            BeanUtil.copyProperties(goodsTagVO, newTag);

            List<String> tagDisPosList = goodsTagVO.getGoodsTagDisplayPosition();
            if (!CollectionUtils.isEmpty(tagDisPosList)) {
                newTag = this.setTagDisPos(tagDisPosList, newTag);
            }

            newTag.setStatus(oldTags.getStatus());
            newTag.setType(oldTags.getType());
            newTag.setUpdateTime(DateUtil.getDateline());
            this.daoSupport.update(newTag, tagId);

            //2、删除商品关联关系，并更新redis
            editTag(tagId.toString(), newTag.getStatus());
        } else {
            //新增
            TagsDO tagsDO = new TagsDO();
            BeanUtil.copyProperties(goodsTagVO, tagsDO);

            tagsDO.setSellerId(sellerId);
            tagsDO.setType(GoodsTagType.CUSTOM.getIndex());
            tagsDO.setStatus(GoodsTagStatus.ENABLE.getIndex());
            tagsDO.setCreateTime(DateUtil.getDateline());
            tagsDO.setUpdateTime(DateUtil.getDateline());
            List<String> tagDisPosList = goodsTagVO.getGoodsTagDisplayPosition();
            if (!CollectionUtils.isEmpty(tagDisPosList)) {
                tagsDO = this.setTagDisPos(tagDisPosList, tagsDO);
            }

            this.daoSupport.insert(tagsDO);
        }

    }

    @Override
    @Transactional(value = "goodsTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    public void deleteTag(String tagIds, Integer status) {
        // 1、删除标签
        String sql = "update es_tags set `status` = " + status + " , update_time=now() where tag_id in  (" + tagIds + ")";
        this.daoSupport.execute(sql);
        // 2、删除商品关联关系，并更新redis
        editTag(tagIds, status);
    }


    @Override
    @Transactional(value = "goodsTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void addShopTags(Integer sellerId) {

        TagType[] tags = TagType.values();
        for (TagType tag : tags) {
            TagsDO tagDO = new TagsDO(tag.tagName(), sellerId, tag.mark(), tag.status(), tag.shopHomePageStauts(),
                    tag.goodsListPageStauts(), tag.goodsDetailsPageStauts(), tag.color(), tag.style(), tag.priority());
            tagDO.setType(GoodsTagType.SYSTEM_DEFAULT.getIndex());
            tagDO.setPermanentEnable(GoodsTagStatus.ENABLE.getIndex());
            tagDO.setCreateTime(DateUtil.getDateline());
            tagDO.setUpdateTime(DateUtil.getDateline());
            this.daoSupport.insert(tagDO);
        }

    }


    @Override
    public Page queryTagGoods(Integer tagId, Integer pageNo, Integer pageSize) {

        Seller seller = UserContext.getSeller();
        TagsDO tag = this.getModel(tagId);
        if (tag == null || !tag.getSellerId().equals(seller.getSellerId())) {
            throw new ServiceException(GoodsErrorCode.E309.code(), "无权操作");
        }

        String sql = "select g.goods_id,g.goods_name,g.price,g.buy_count,g.enable_quantity,g.thumbnail from es_tag_goods r LEFT JOIN es_goods g ON g.goods_id=r.goods_id  "
                + "where g.disabled=1 and g.market_enable=1 and r.tag_id=? ";

        return this.daoSupport.queryForPage(sql, pageNo, pageSize, tagId);
    }


    @Override
    @Transactional(value = "goodsTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    public void saveTagGoods(Integer tagId, Integer[] goodsIds, Integer allGoods) {

        //1、获取当前店铺ID及标签信息，如果标签不属于当前店铺，返回无权操作
        Integer sellerId = UserContext.getSeller().getSellerId();
        TagsDO tag = this.getModel(tagId);
        if (tag == null || !tag.getSellerId().equals(sellerId)) {
            throw new ServiceException(GoodsErrorCode.E309.code(), "无权操作");
        }

        if (goodsIds[0] != -1) {
            //2、校验商品是否全部都是当前店铺的，否则返回错误
            List<Object> term = new ArrayList<>();
            String idStr = SqlUtil.getInSql(goodsIds, term);
            term.add(sellerId);
            Integer count = this.daoSupport.queryForInt("select count(1) from es_goods where goods_id in (" + idStr + ") and seller_id = ?", term.toArray());
            if (goodsIds.length != count) {
                throw new ServiceException(GoodsErrorCode.E309.code(), "无权操作");
            }
        }

        // 3、更新标签信息，标记当前标签为所有商品的标签
        String updateTag = "update es_tags set all_goods=" + allGoods + " where tag_id=" + tagId;
        this.daoSupport.execute(updateTag);

        //4、删除原来的关联关系
        String sql = "delete from es_tag_goods where tag_id = ?";
        this.daoSupport.execute(sql, tagId);

        //5、如果标签下不保存商品，则在这里返回
        if (goodsIds[0] == -1) {
            //表示这个标签下不保存商品
            return;
        }

        //6、添加新的标签与商品的关联关系
        List<TagGoodsDO> tagGoodsDOS = new ArrayList<>();
        for (Integer goodsId : goodsIds) {
            TagGoodsDO tagGoods = new TagGoodsDO(tagId, goodsId);
            tagGoodsDOS.add(tagGoods);
        }
        //7、批量添加数据库
        this.daoSupport.batchInsert("es_tag_goods", tagGoodsDOS);

        // 8、如果选择关联所有商品，则更新redis中店铺的标签信息
        if (allGoods == 0) {
            this.amqpTemplate.convertAndSend(AmqpExchange.SHOP_TAG_CHANGE,
                    AmqpExchange.SHOP_TAG_CHANGE + "_ROUTING", new ArrayList<Integer>(sellerId));
        }
    }


    @Override
    public List<GoodsSelectLine> queryTagGoods(Integer sellerId, Integer num, String mark) {

        String sql = "select g.goods_id,g.goods_name,g.price,g.sn,g.thumbnail,g.big,g.quantity,g.buy_count from es_tag_goods r "
                + " inner join es_goods g on g.goods_id=r.goods_id "
                + " inner join es_tags t on t.tag_id = r.tag_id"
                + " where g.disabled=1 and g.market_enable=1 and t.mark = ? and t.seller_id = ?   limit 0,? ";

        return this.daoSupport.queryForList(sql, GoodsSelectLine.class, mark, sellerId, num);
    }

    @Override
    public TagsDO getModel(Integer id) {

        return this.daoSupport.queryForObject(TagsDO.class, id);
    }


    @Override
    public TagGoodsNum queryGoodsNumByShopId(Integer shopId) {

        String sql = "select count(1) count,t.mark from es_tags t left join es_tag_goods tg on t.tag_id=tg.tag_id where t.seller_id = ?  group by t.tag_id";

        List<Map> list = this.daoSupport.queryForList(sql, shopId);

        Integer hotNum = 0;
        Integer newNum = 0;
        Integer recommendNum = 0;

        if (StringUtil.isNotEmpty(list)) {
            for (Map map : list) {
                String mark = map.get("mark").toString();
                Integer count = Integer.valueOf(map.get("count").toString());

                switch (mark) {
                    case "hot":
                        hotNum = count;
                        break;
                    case "new":
                        newNum = count;
                        break;
                    case "recommend":
                        recommendNum = count;
                        break;
                    default:
                        break;
                }

            }
        }

        TagGoodsNum tagGoodsNum = new TagGoodsNum(hotNum, newNum, recommendNum);

        return tagGoodsNum;
    }

    /**
     * 获取商品所有的标签
     *
     * @param goodsIdAndSellerId map(商品ID，店铺ID)
     * @return map(商品ID ， 店铺ID)
     */
    @Override
    public Map<Integer, List<TagsDTO>> getAllGoodsTags(Map<Integer, Integer> goodsIdAndSellerId) {
        // 1、校验参数
        if (goodsIdAndSellerId == null) {
            return null;
        }
        List<Integer> goodsIds = new ArrayList<>(goodsIdAndSellerId.keySet());
        if (CollectionUtils.isEmpty(goodsIds)) {
            return null;
        }
        List<Integer> sellerIds = new ArrayList<>(goodsIdAndSellerId.values());
        if (CollectionUtils.isEmpty(sellerIds)) {
            return null;
        }

        // 2、获取商品关联的标签
        String tagSql = "SELECT t.*,tg.goods_id FROM es_tag_goods tg LEFT JOIN es_tags t ON tg.tag_id=t.tag_id \n" +
                "WHERE t.`status` = 0 and tg.goods_id in (" + StringUtil.listToString(goodsIds, ",") + ")";
        String sellerIdString = StringUtil.listToString(sellerIds.stream().distinct().collect(Collectors.toList()), ",");
        tagSql = tagSql.concat(" and seller_id in (" + sellerIdString + ")");
        List<TagsDTO> partGoodsList = this.daoSupport.queryForList(tagSql, TagsDTO.class);

        // 3、封装map，以商品为维度分组
        Map<Integer, List<TagsDTO>> goodsTagMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(partGoodsList)) {
            goodsTagMap = partGoodsList.stream().filter(tagsDTO -> tagsDTO.getGoodsId() != null).collect(Collectors.groupingBy(TagsDTO::getGoodsId, Collectors.toList()));
        }

        // 4、把所有商品都有的标签加进去
        for (Integer goodsId : goodsIds) {
            List<TagsDTO> tagsDTOList = new ArrayList<>();
            if (goodsTagMap.get(goodsId) != null) {
                tagsDTOList.addAll(goodsTagMap.get(goodsId));
            }
            //当前商品所属店铺标记所有商品的标签
            List<TagsDTO> sellerTagsList = this.getTagsByCache(goodsIdAndSellerId.get(goodsId));
            if (!CollectionUtils.isEmpty(sellerTagsList)) {
                tagsDTOList.addAll(sellerTagsList);
            }
            //去重
            tagsDTOList = tagsDTOList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getTagId()))), ArrayList::new));
            goodsTagMap.put(goodsId, tagsDTOList);
        }
        return goodsTagMap;
    }

    @Override
    public List<TagsDTO> tagsFilterAndComp(String type, List<TagsDTO> tagsDTOList) {
        List<TagsDTO> result = new ArrayList<>();
        if (!CollectionUtils.isEmpty(tagsDTOList)) {
            if (type.equals("shopHomeTags")) {
                result = tagsDTOList.stream().filter(tagsDTO -> tagsDTO.getShopHomePage() == GoodsTagPageStatus.SHOW.getIndex()).collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(result)) {
                    result = result.stream().sorted(Comparator.comparing(TagsDTO::getPriority).reversed()).collect(Collectors.toList());
                }
            }

            if (type.equals("goodsListTags")) {
                result = tagsDTOList.stream().filter(tagsDTO -> tagsDTO.getGoodsListPage() == GoodsTagPageStatus.SHOW.getIndex()).collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(result)) {
                    result = result.stream().sorted(Comparator.comparing(TagsDTO::getPriority).reversed()).collect(Collectors.toList());
                }
            }

            if (type.equals("goodsDetailsTags")) {
                result = tagsDTOList.stream().filter(tagsDTO -> tagsDTO.getGoodsDetailsPage() == GoodsTagPageStatus.SHOW.getIndex()).collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(result)) {
                    result = result.stream().sorted(Comparator.comparing(TagsDTO::getPriority).reversed()).collect(Collectors.toList());
                }
            }
        }
        return result;
    }

    //从缓存中获取店铺关联所有商品的标签
    private List<TagsDTO> getTagsByCache(Integer sellerId) {
        //1、从缓存中获取店铺关联所有商品的标签
        List<TagsDTO> allGoodsTagList = (List<TagsDTO>) cache.get(CachePrefix.SHOP_TAG.getPrefix() + sellerId);
        if (CollectionUtils.isEmpty(allGoodsTagList)) {
            // 2、如果缓存中没有就从数据库中查询
            //String sql = "select * from es_tags where seller_id =? and `status` = 0 and all_goods=0";
            String sql = "select * from es_tags where seller_id =? and `status` = 0 ";

            allGoodsTagList = this.daoSupport.queryForList(sql, TagsDTO.class, sellerId);

            //3、把店铺关联所有商品的标签放入缓存
            cache.put(CachePrefix.SHOP_TAG.getPrefix() + sellerId, allGoodsTagList);
        }
        return allGoodsTagList;
    }

    private void editTag(String tagIds, Integer status) {
        // 1、查询该标签关联的商品
        String queryGoodsId = "select t.*,tg.goods_id from es_tags t LEFT JOIN es_tag_goods tg ON t.tag_id=tg.tag_id where t.tag_id in (" + tagIds + ")";
        List<TagsDTO> tagsList = this.daoSupport.queryForList(queryGoodsId, TagsDTO.class);
        // 2、商品不为空，需要更新商品索引，并删除关联关系
        if (!CollectionUtils.isEmpty(tagsList)) {
            // 3、先删除商品和标签的关联
            if (status == GoodsTagStatus.DISABLE.getIndex()) {
                String deleteGoodsTag = "delete from es_tag_goods where tag_id in (" + tagIds + ")";
                this.daoSupport.execute(deleteGoodsTag);
            }

            //商品启用、禁用、修改、删除，都要更新redis中店铺的标签信息(如果变动的标签中不包含所有商品都有的标签，就不需要更新)
            List<Integer> sellerIds = tagsList.stream().filter(tagsDTO -> tagsDTO.getAllGoods()==0).map(TagsDTO::getSellerId).distinct().collect(Collectors.toList());
            if(!CollectionUtils.isEmpty(sellerIds)){
                this.amqpTemplate.convertAndSend(AmqpExchange.SHOP_TAG_CHANGE,
                        AmqpExchange.SHOP_TAG_CHANGE + "_ROUTING", new ArrayList<Integer>(sellerIds));
            }
        }

    }

    //保存标签展示位置
    private TagsDO setTagDisPos(List<String> tagDisPosList, TagsDO tagsDO) {
        tagsDO.setGoodsDetailsPage(GoodsTagPageStatus.HIDE.getIndex());
        tagsDO.setGoodsListPage(GoodsTagPageStatus.HIDE.getIndex());
        tagsDO.setShopHomePage(GoodsTagPageStatus.HIDE.getIndex());
        for (String tagDisPos : tagDisPosList) {
            if (tagDisPos.equals(GoodsTagDisplayPosition.GOODS_DETAILS_PAGE.getDescribe())) {
                tagsDO.setGoodsDetailsPage(GoodsTagDisplayPosition.getIndexByText(tagDisPos));
            }
            if (tagDisPos.equals(GoodsTagDisplayPosition.GOODS_LIST_PAGE.getDescribe())) {
                tagsDO.setGoodsListPage(GoodsTagDisplayPosition.getIndexByText(tagDisPos));
            }
            if (tagDisPos.equals(GoodsTagDisplayPosition.SHOP_HOME_PAGE.getDescribe())) {
                tagsDO.setShopHomePage(GoodsTagDisplayPosition.getIndexByText(tagDisPos));
            }
        }
        return tagsDO;
    }
}
